package com.inetools.gwetons.shared.logging;

import com.google.gwt.core.client.GWT;
import com.inetools.gwetons.client.logging.LogUtilGinjector;

/**
 * To obtain LogUtil instance via LogUtilFactoryIntf interface. 
 * You may use JsniLogUtilFactoryInstanceHolder class to get instance of this class for your convenience.
 * @author ay
 */
public class LogUtilFactory implements LogUtilFactoryIntf {
	private static LogUtilGinjector logUtilGinjector;
		public synchronized static LogUtilGinjector getLogUtilGinjector() {
			if ( LogUtilFactory.logUtilGinjector == null) {
				if ( GWT.isClient()) {
					LogUtilGinjector logUtilGinjectorObj = GWT.create( LogUtilGinjector.class);
					LogUtilFactory.setLogUtilGinjector( logUtilGinjectorObj);
				}
				// GWT compiler throws error when code of setting LogUtilInjector instance for 
				// non-JavaScript case is here; therefore, for non-JavaScript case, LogUtilInjector 
				// instance needs to be manually set.
//TODO I may be able to work around GWT compiler error by using Proxy. 
			}
			return LogUtilFactory.logUtilGinjector;
		}
		
		/**
		 * Set LogUtilGinjector instance to LogUtilFactory.logUtilGinjector static member field 
		 * what will be used to generate LogUtil instance via getLogUtil method.
		 * LogUtilGinModule.class will be used as default when no LogUtilGinjector instance has not 
		 * been set via this method.
		 * @param logUtilGinjector
		 */
		public synchronized static void setLogUtilGinjector( LogUtilGinjector logUtilGinjector) {
			LogUtilFactory.logUtilGinjector = logUtilGinjector;
			LogUtilFactory.setLogUtilFactoryLogUtil( null);
		}
	
	// Logging objects for LogUtilFactory itself --------------------------------------------------
	private static LogUtil logUtilFactoryLogUtil;
		public synchronized static LogUtil getLogUtilFactoryLogUtil() {
			if ( LogUtilFactory.logUtilFactoryLogUtil == null) {
				LogUtil logUtilObj = LogUtilFactory.getLogUtilGinjector().getLogUtil();
					logUtilObj.setUpLogger( LogUtilFactory.class.getName());
				LogUtilFactory.setLogUtilFactoryLogUtil( logUtilObj);
			}
			return LogUtilFactory.logUtilFactoryLogUtil;
		}
		/**
		 * Set LogUtil instance to be used for logging for this LogUtilFactory object.
		 * @param logUtilFactoryLogUtil
		 */
		public synchronized static void setLogUtilFactoryLogUtil( LogUtil logUtilFactoryLogUtil) {
			LogUtilFactory.logUtilFactoryLogUtil = logUtilFactoryLogUtil;
		}
	// --------------------------------------------------------------------------------------------
	
	protected LogUtilFactory() {
	}
	
	// LogUtilFactoryIntf method -------------------------------------------------------------
	@Override
	public LogUtil getLogUtil( String loggerName) {
		String methodName = "getLogUtil";
		LogUtil logUtilFactoryLogUtil = LogUtilFactory.getLogUtilFactoryLogUtil();
		logUtilFactoryLogUtil.entering(
				methodName, 
				new Object[]{ "loggerName(=" + ((loggerName == null) ? "null" : loggerName) + ")"}
				);

		LogUtil logUtil = LogUtilFactory.getLogUtilGinjector().getLogUtil();
			logUtil.setUpLogger( loggerName);

		logUtilFactoryLogUtil.exiting( methodName, logUtil);
		return logUtil;
	}
	// --------------------------------------------------------------------------------------------
	
	public static LogUtil getLogUtil( String loggerName, LogUtilFactoryIntf factoryInstance) {
		String methodName = "getLogUtil";
		LogUtil logUtilFactoryLogUtil = LogUtilFactory.getLogUtilFactoryLogUtil();
		logUtilFactoryLogUtil.entering( 
				methodName, 
				new Object[]{ 
					"loggerName(=" + ((loggerName == null) ? "null" : loggerName) + ")", 
					"factoryInstance(=" + ((factoryInstance == null) 
							? "null" : factoryInstance.toString()) + ")"
					}
				);
		
		LogUtilFactoryIntf factory = factoryInstance;
			if (factory == null) {
				factory = LogUtilFactoryInstanceHolder.getLogutilfactory();
			}
		LogUtil logUtil = factory.getLogUtil( loggerName);
		
		logUtilFactoryLogUtil.exiting( methodName, logUtil.toString());
		return logUtil;
	}
	
	
	/**
	 * Convenient method to be used in static method. <br />
	 * BY making to get LogUtil instance through this method, it will be easy to
	 * swap LogUtil instance.
	 * 
	 * @param instance
	 * @param loggerName
	 *            : Ignored when instance input is LogUtil instance but null.
	 * @param factoryInstance
	 *            : Ignored when instance input is LogUtil instance but null.
	 *            When instance input is null, this will be used with loggerName
	 *            input to instantiate LogUtil object. When this is null, then
	 *            LogUtilFactory.FacoryInstance will be used as default
	 *            LogUtilFactoryIntf instance.
	 * @return
	 */
	public static LogUtil getLogUtil(
			LogUtil instance, String loggerName, LogUtilFactoryIntf factoryInstance) {
		String methodName = "getLogUtil";
		LogUtil logUtilFactoryLogUtil = LogUtilFactory.getLogUtilFactoryLogUtil();
		logUtilFactoryLogUtil.entering( 
				methodName, 
				new Object[]{
						"instance(=" + ((instance == null) ? "null" : instance.toString()) + ")", 
						"loggerName(=" + ((loggerName == null) ? "null" : loggerName) + ")", 
						"factoryInstance(=" + ((factoryInstance == null) ? 
								"null" : factoryInstance.toString()) + ")"
						}
				);
		
		if ( instance != null) {
			logUtilFactoryLogUtil.exiting( methodName, instance.toString());
			return instance;
		}

		LogUtil logUtil = LogUtilFactory.getLogUtil( loggerName, factoryInstance);
		
		logUtilFactoryLogUtil.exiting( methodName, logUtil.toString());
		return logUtil;
	}
	
}
